/*
 *    GeoTools - The Open Source Java GIS Toolkit
 *    http://geotools.org
 *
 *    (C) 2011, Open Source Geospatial Foundation (OSGeo)
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License as published by the Free Software Foundation;
 *    version 2.1 of the License.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 */

package org.geotools.geotools_swing.old;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

/**
 * Displays an {@code Exception} to the user in a modal dialog. This class is not a Swing
 * component itself, rather it provides static {@code showDialog} methods to create and
 * display dialogs safely from any thread.
 * <p>
 * 
 * Example of use:
 * 
 * <pre><code>
 * try {
 * 
 *     // ...something awful happens in here...
 * 
 * } catch (SomeException ex) {
 *     JExceptionReporter.showDialog(ex, "Bummer, it failed again");
 * }
 * </code></pre>
 * 
 * @author Michael Bedward
 * @since 8.0
 * @source $URL$
 * @version $Id$
 */
public class JExceptionReporter {
    
    // Hidden constructor.
    private JExceptionReporter() {}

    
    /**
     * Displays an exception in a dialog where the title is the 
     * exception class name and the body of the dialog shows the 
     * exception message.
     * <p>
     * It is safe to call this method from any thread.
     * 
     * @param exception exception to display
     */
    public static void showDialog(Throwable exception) {
        showDialog(exception, null);
    }
    
    /**
     * Displays an exception in a dialog where the title is the 
     * exception class name and the body of the dialog shows the 
     * given message.
     * <p>
     * It is safe to call this method from any thread.
     * 
     * @param exception exception to display
     * @param message message to display; if {@code null} or empty the 
     *     message will be taken from the exception
     */
    public static void showDialog(final Throwable exception, final String message) {
        if (exception == null) {
            throw new IllegalArgumentException("exception must not be null");
        }

        if (SwingUtilities.isEventDispatchThread()) {
            doShowDialog(exception, message);

        } else {
            SwingUtilities.invokeLater(new Runnable() {

                @Override
                public void run() {
                    doShowDialog(exception, message);
                }
            });
        }
    }
    
    private static void doShowDialog(Throwable exception, String message) {
        String title = exception.getClass().getSimpleName();
        
        if (empty(message)) {
            message = exception.getLocalizedMessage();
            
            if (empty(message)) {
                message = "UnspecifiedError";
            }
        }
        
        ReportingDialog dialog = new ReportingDialog(title, message);
        DialogUtils.showCentred(dialog);
    }
    
    private static boolean empty(String s) {
        return s == null || s.trim().length() == 0;
    }


    /**
     * The dialog used to display the {@code Exception}. It is package-private
     * rather than private to enable unit tests.
     */
    static class ReportingDialog extends AbstractSimpleDialog {
        /**
		 * 
		 */
		private static final long serialVersionUID = 1L;
		private static final int DEFAULT_WIDTH = 400;
        @SuppressWarnings("unused")
		private static final int DEFAULT_HEIGHT = 200;
        private static final int MARGIN = 5;
        
        private final String message;

        private ReportingDialog(String title, String message) {
            super(title);
            this.message = message;
            
            setDefaultCloseOperation(DISPOSE_ON_CLOSE);
            initComponents();
        }

        @Override
        public JPanel createControlPanel() {
            JPanel panel = new JPanel();
            panel.setBorder(BorderFactory.createCompoundBorder(
                    BorderFactory.createMatteBorder(0, 0, 1, 0, Color.BLACK),
                    BorderFactory.createEmptyBorder(MARGIN, MARGIN, MARGIN, MARGIN)));
            
            String text = String.format("<html>%s</html>", message);
            int w = DEFAULT_WIDTH - 2 * MARGIN;
            Dimension dim = DialogUtils.getHtmlLabelTextExtent(text, w, true);
            
            JLabel label = new JLabel(text);
            label.setPreferredSize(dim);
            panel.add(label);
            
            panel.setPreferredSize(new Dimension(DEFAULT_WIDTH, dim.height + 4*MARGIN ));
            return panel;
        }

        @Override
        protected JPanel createButtonPanel() {
            JPanel panel = new JPanel();
            
            JButton button = new JButton("Close");
            button.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    onOK();
                }
            });
            
            panel.add(button);
            return panel;
        }

        @Override
        public void onOK() {
            closeDialog();
        }
        
    }
    
}
